﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using Caliburn.Micro;
using Caliburn.Micro.Extensions;
using CoProjectDF.Repository;
using CoProjectModel;
using Coproject.Events;
using Coproject.Framework;
using Coproject.ViewModels.Interfaces;

namespace Coproject.ViewModels
{
    [ExportModule(30)]
    public class ToDoListsViewModel : Conductor<IToDoItemViewModel>.Collection.OneActive, IModule,
                                      IHandle<ToDoItemUpdatedEvent>
    {
        private readonly IToDoListRepository _repository;
        private BindableCollection<ToDoList> _todolists;

        [ImportingConstructor]
        public ToDoListsViewModel(IEventAggregator eventAggregator, IToDoListRepository repository)
        {
            DisplayName = "To Do";
            Description = "To-do lists";
            _repository = repository;
            eventAggregator.Subscribe(this);
        }

        [Import(RequiredCreationPolicy = CreationPolicy.Shared)]
        public IBusyWatcher Busy { get; set; }

        public string Filter { get; set; }

        public BindableCollection<ToDoList> Lists
        {
            get { return _todolists; }
            private set
            {
                _todolists = value;
                NotifyOfPropertyChange(() => Lists);
            }
        }

        #region IHandle<ToDoItemUpdatedEvent> Members

        public void Handle(ToDoItemUpdatedEvent message)
        {
            LoadData().ToSequential().Execute(null);
        }

        #endregion

        #region IModule Members

        public string Description { get; private set; }

        #endregion

        public void Start()
        {
            LoadData().ToSequential().Execute(null);
        }

        protected override void OnInitialize()
        {
            base.OnInitialize();
            Start();
        }

        /// <summary>
        /// Method called from Search Button on View
        /// Demonstrates a clean syntax using a disposable Busy.GetTicket and
        /// CoroutineFns.AsResult converting a non-IResult repository method.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<IResult> LoadData()
        {
            Exception error = null;
            using (Busy.GetTicket())
            {
                //When using DevelopmentEntityManagerProvider() the application needs an Initialisation
                // for use in Anonymous mode.
                yield return CoroutineFns.AsResult(_repository.Initialise);

                yield return CoroutineFns.AsResult(
                    () => _repository.GetToDoLists("Name",
                            result => Lists = new BindableCollection<ToDoList>(result),
                            e => error = e)); // Marks error as handled, so we always come back from the yield
            }

            if (error != null)
                MessageBox.Show(error.Message, "System Error", MessageBoxButton.OK);
        }

        /// <summary>
        /// Not used. Just shows the conventional method
        /// of accessing the repository, where a INotifyCompleted is returned,
        /// but requires a DevForce reference.
        /// </summary>
        //public void LoadData2()
        //{
        //    Busy.AddWatch();
        //    INotifyCompleted nc = _repository.GetToDoLists("Name",
        //                                                   todolists =>
        //                                                   {
        //                                                       Lists = new BindableCollection<ToDoList>(todolists);
        //                                                       Busy.RemoveWatch();
        //                                                   });

        //    nc.WhenCompleted((a) =>
        //                         {
        //                             /* Do Something */
        //                         });
        //}

        /// <summary>
        /// Called by selecting a ToDoList, to obtain the Child in a Parent-Child relationship.
        /// IToDoItemViewModel is a ViewModel that does not implement IResult,
        /// but where a method GetToDoItem() returns IEnumerable<IResult> to enable
        /// a Caliburn.Micro CoRoutine to be used.
        /// </summary>
        /// <param name="item"></param>
        /// <returns>Caliburn Micro CoRoutine IEnumerable<IResult></returns>
        public IEnumerable<IResult> OpenItemDetail(ToDoItem item)
        {
            IToDoItemViewModel editor = Items.FirstOrDefault(x => x.Item.ToDoItemID == item.ToDoItemID) ??
                                        IoC.Get<IToDoItemViewModel>();

            Exception error = null;
            using (Busy.GetTicket())
            {
                yield return editor.GetToDoItem(item.ToDoItemID, null, e => error = e);
            }

            if (error != null)
                MessageBox.Show(error.Message, "System Error", MessageBoxButton.OK);
            else
                ActivateItem(editor);
        }
    }
}